
# 从 collections 模块导入 defaultdict，用于创建默认值的字典
from collections import defaultdict
# 从 enum 模块导入 Enum，用于创建枚举类型
from enum import Enum

# 从 qtpy 库导入 QtCore 和 QtGui 模块，提供 Qt 框架的核心功能和图形用户界面功能
from qtpy import QtCore, QtGui

# 从 src 核心的通用模块导入所有内容
from src.Core.Common import *


class InputActionType(Enum):
    """
    定义输入动作的类型枚举类。
    目前支持鼠标和键盘两种输入动作类型。
    """
    Mouse = 1
    Keyboard = 2


class InputAction(object):
    """
    表示一个输入动作，包含动作名称、类型、组以及相关的鼠标、键盘和修饰键信息。
    可以将输入动作序列化为 JSON 数据，也可以从 JSON 数据中反序列化。
    """
    def __init__(
            self,
            name="defaultName",
            actionType=InputActionType.Keyboard,
            group="default",
            mouse=QtCore.Qt.NoButton,
            key=None,
            modifiers=QtCore.Qt.NoModifier,
    ):
        """
        初始化输入动作对象。

        :param name: 输入动作的名称，默认为 "defaultName"
        :param actionType: 输入动作的类型，默认为键盘输入
        :param group: 输入动作所属的组，默认为 "default"
        :param mouse: 鼠标按钮，默认为无按钮
        :param key: 键盘按键，默认为 None
        :param modifiers: 键盘修饰键，默认为无修饰键
        """
        self.__actionType = actionType
        self._name = name
        self._group = group
        self.__data = {"mouse": mouse, "key": key, "modifiers": modifiers}

    def __str__(self):
        """
        将输入动作转换为字符串表示形式。

        :return: 包含修饰键、鼠标按钮和键盘按键的字符串
        """
        return "{0} {1} {2}".format(
            QtGui.QKeySequence(self.getModifiers()).toString(),
            self.getMouseButton().name.decode("utf=8"),
            QtGui.QKeySequence(self.getKey()).toString(),
        )

    @property
    def group(self):
        """
        获取输入动作所属的组。

        :return: 输入动作所属的组名
        """
        return self._group

    @property
    def actionType(self):
        """
        获取输入动作的类型。

        :return: 输入动作的类型枚举值
        """
        return self.__actionType

    def __eq__(self, other):
        """
        判断两个输入动作是否相等。

        :param other: 另一个输入动作对象
        :return: 如果两个输入动作的鼠标按钮、键盘按键和修饰键都相同，则返回 True，否则返回 False
        """
        sm = self.__data["mouse"]
        sk = self.__data["key"]
        smod = self.__data["modifiers"]
        om = other.getData()["mouse"]
        ok = other.getData()["key"]
        omod = other.getData()["modifiers"]
        return all([sm == om, sk == ok, smod == omod])

    def __ne__(self, other):
        """
        判断两个输入动作是否不相等。

        :param other: 另一个输入动作对象
        :return: 如果两个输入动作的鼠标按钮、键盘按键和修饰键有任何一个不同，则返回 True，否则返回 False
        """
        sm = self.__data["mouse"]
        sk = self.__data["key"]
        smod = self.__data["modifiers"]
        om = other.getData()["mouse"]
        ok = other.getData()["key"]
        omod = other.getData()["modifiers"]
        return not all([sm == om, sk == ok, smod == omod])

    def getName(self):
        """
        获取输入动作的名称。

        :return: 输入动作的名称
        """
        return self._name

    def getData(self):
        """
        获取输入动作的鼠标、键盘和修饰键信息。

        :return: 包含鼠标按钮、键盘按键和修饰键的字典
        """
        return self.__data

    def setMouseButton(self, btn):
        """
        设置输入动作的鼠标按钮。

        :param btn: 要设置的鼠标按钮，必须是 QtCore.Qt.MouseButton 类型
        :raises AssertionError: 如果传入的参数不是 QtCore.Qt.MouseButton 类型
        """
        assert isinstance(btn, QtCore.Qt.MouseButton)
        self.__data["mouse"] = btn

    def getMouseButton(self):
        """
        获取输入动作的鼠标按钮。

        :return: 鼠标按钮
        """
        return self.__data["mouse"]

    def setKey(self, key=None):
        """
        设置输入动作的键盘按键。

        :param key: 要设置的键盘按键，必须是 QtCore.Qt.Key 类型，默认为 None
        :raises AssertionError: 如果传入的参数不是 QtCore.Qt.Key 类型
        """
        if key is None:
            key = []
        assert isinstance(key, QtCore.Qt.Key)
        self.__data["key"] = key

    def getKey(self):
        """
        获取输入动作的键盘按键。

        :return: 键盘按键
        """
        return self.__data["key"]

    def setModifiers(self, modifiers=QtCore.Qt.NoModifier):
        """
        设置输入动作的键盘修饰键。

        :param modifiers: 要设置的键盘修饰键，默认为无修饰键
        """
        self.__data["modifiers"] = modifiers

    def getModifiers(self):
        """
        获取输入动作的键盘修饰键。

        :return: 键盘修饰键
        """
        return self.__data["modifiers"]

    @staticmethod
    def _modifiersToList(mods):
        """
        将键盘修饰键转换为列表。

        :param mods: 键盘修饰键
        :return: 包含所有激活的键盘修饰键的列表
        """
        result = []
        if mods & QtCore.Qt.ShiftModifier:
            result.append(QtCore.Qt.ShiftModifier)
        if mods & QtCore.Qt.ControlModifier:
            result.append(QtCore.Qt.ControlModifier)
        if mods & QtCore.Qt.AltModifier:
            result.append(QtCore.Qt.AltModifier)
        if mods & QtCore.Qt.MetaModifier:
            result.append(QtCore.Qt.MetaModifier)
        if mods & QtCore.Qt.KeypadModifier:
            result.append(QtCore.Qt.KeypadModifier)
        if mods & QtCore.Qt.GroupSwitchModifier:
            result.append(QtCore.Qt.GroupSwitchModifier)
        return result

    @staticmethod
    def _listOfModifiersToEnum(modifiersList):
        """
        将修饰键列表转换为单个枚举值。

        :param modifiersList: 包含修饰键的列表
        :return: 组合后的修饰键枚举值
        """
        result = QtCore.Qt.NoModifier
        for mod in modifiersList:
            result = result | mod
        return result

    def toJson(self):
        """
        将输入动作序列化为 JSON 数据。

        :return: 包含输入动作信息的字典，可以直接转换为 JSON 格式
        """
        saveData = {"name": self._name,
                    "group": self._group,
                    "mouse": int(self.__data["mouse"].value),
                    "actionType": self.actionType.value}
        key = self.__data["key"]
        saveData["key"] = int(key) if key is not None else None

        modifiersList = self._modifiersToList(self.__data["modifiers"])

        saveData["modifiers"] = [i.value for i in modifiersList]
        return saveData

    def fromJson(self, jsonData):
        """
        从 JSON 数据中反序列化输入动作。

        :param jsonData: 包含输入动作信息的字典
        :return: 反序列化后的输入动作对象，如果反序列化失败则返回 None
        """
        try:
            self._name = jsonData["name"]
            self._group = jsonData["group"]
            self.__data["mouse"] = QtCore.Qt.MouseButton(jsonData["mouse"])
            keyJson = jsonData["key"]
            self.__data["key"] = (
                QtCore.Qt.Key(keyJson) if isinstance(keyJson, int) else None
            )
            self.__data["modifiers"] = self._listOfModifiersToEnum(
                [QtCore.Qt.KeyboardModifier(i) for i in jsonData["modifiers"]]
            )
            self.__actionType = InputActionType(jsonData["actionType"])
            return self
        except:
            return None


@SingletonDecorator
class InputManager(object):
    """
    输入管理器单例类，用于管理所有注册的输入动作。
    可以注册、加载和序列化输入动作。
    """

    def __init__(self, *args, **kwargs):
        """
        初始化输入管理器，创建一个默认字典来存储输入动作。
        """
        self.__actions = defaultdict(list)

    def __getitem__(self, key):
        """
        根据动作名称获取对应的输入动作列表。

        :param key: 输入动作的名称
        :return: 如果存在对应的输入动作列表，则返回该列表；否则返回空列表
        """
        # 尝试通过名称查找输入动作
        if key in self.__actions:
            return self.__actions[key]
        return []

    def __contains__(self, item):
        """
        检查输入动作是否已注册。

        :param item: 输入动作对象
        :return: 如果输入动作已注册，则返回 True；否则返回 False
        """
        return item.getName() in self.__actions

    def getData(self):
        """
        获取所有注册的输入动作。

        :return: 包含所有输入动作的默认字典
        """
        return self.__actions

    def registerAction(self, action):
        """
        注册一个输入动作。

        :param action: 要注册的输入动作对象
        """
        if action not in self.__actions[action.getName()]:
            self.__actions[action.getName()].append(action)

    def loadFromData(self, data):
        """
        从数据中加载输入动作。

        :param data: 包含输入动作信息的字典
        """
        for actionName, actionVariants in data.items():
            for variant in actionVariants:
                actionInstance = InputAction().fromJson(variant)
                self.registerAction(actionInstance)

    def serialize(self):
        """
        将所有注册的输入动作序列化为 JSON 数据。

        :return: 包含所有输入动作信息的默认字典，可以直接转换为 JSON 格式
        """
        result = defaultdict(list)
        for actionName in self.__actions:
            for actionVariant in self.__actions[actionName]:
                result[actionName].append(actionVariant.toJson())
        return result